package com.tzy.for10evalue.utils;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cglib.beans.BeanCopier;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author tzy
 * @date 2022/3/10 16:56
 */
public class BeanCopyUtil {
    private static Logger logger = LoggerFactory.getLogger(BeanCopyUtil.class);
    private static final Map<String, BeanCopier> beanCopierMap = Maps.newHashMap();

    /**
     *
     * 拷贝属性
     *
     * @param source
     * @param target
     */
    public static void copyProperties(Object source, Object target) {
        String beanKey = generateKey(source.getClass(), target.getClass(), false);
        BeanCopier copier = null;
        if (!beanCopierMap.containsKey(beanKey)) {
            copier = BeanCopier.create(source.getClass(), target.getClass(), false);
            beanCopierMap.put(beanKey, copier);
        } else {
            copier = beanCopierMap.get(beanKey);
        }
        copier.copy(source, target, null);
    }

    /**
     * te
     * 拷贝属性
     *
     * @param source
     * @param tClass
     */
    public static <T> T copyProperties(Object source, Class<T> tClass) {
        String beanKey = generateKey(source.getClass(), tClass, false);
        BeanCopier copier = null;
        if (!beanCopierMap.containsKey(beanKey)) {
            copier = BeanCopier.create(source.getClass(), tClass, false);
            beanCopierMap.put(beanKey, copier);
        } else {
            copier = beanCopierMap.get(beanKey);
        }
        T o = newInstance(tClass);
        copier.copy(source, o, null);
        return o;
    }


    /**
     * te
     * 拷贝属性
     *
     * @param sourceList
     * @param target
     */
    public static <T> List<T> copyList(List sourceList, Class<T> target) {
        if (CollectionUtils.isEmpty(sourceList)) {
            return Lists.newArrayList();
        }

        Object so = sourceList.get(0);
        String beanKey = generateKey(so.getClass(), target, false);
        BeanCopier copier = null;
        if (!beanCopierMap.containsKey(beanKey)) {
            copier = BeanCopier.create(so.getClass(), target, false);
            beanCopierMap.put(beanKey, copier);
        } else {
            copier = beanCopierMap.get(beanKey);
        }
        ArrayList<T> list = Lists.newArrayList();
        for (Object source : sourceList) {
            T o1 = newInstance(target);
            copier.copy(source, o1, null);
            list.add(o1);
        }
        return list;
    }


    private static <T> T newInstance(Class<T> target) {
        try {
            return (T) target.newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * te
     * 拷贝属性
     *
     * @param source
     * @param target
     */
    public static void copyPropertiesNonNull(Object source, Object target) {
        String beanKey = generateKey(source.getClass(), target.getClass(), true);
        BeanCopier copier = null;
        if (!beanCopierMap.containsKey(beanKey)) {
            copier = BeanCopier.create(source.getClass(), target.getClass(), true);
            beanCopierMap.put(beanKey, copier);
        } else {
            copier = beanCopierMap.get(beanKey);
        }
        copier.copy(source, target, new BeanCopyUtil.CopyConverter(target));
    }


    private static String generateKey(Class<?> class1, Class<?> class2, Boolean flag) {
        return class1.toString() + class2.toString() + flag;
    }

    static class CopyConverter implements org.springframework.cglib.core.Converter {
        private Object targetObject;

        @Override
        public Object convert(Object o, Class aClass, Object o1) {
            try {
                if (ObjectUtils.isEmpty(o)) {
                    String name = StringUtils.substring(ObjectUtils.nullSafeToString(o1), 3);
                    String fiedName = StringUtils.uncapitalize(name);
                    return FieldUtils.readField(targetObject, fiedName, true);
                }
            } catch (Exception e) {
                logger.error("o ={},class={},o1={}", JSON.toJSONString(o), aClass.getName(), JSON.toJSONString(o1), e);
            }
            return o;
        }

        public CopyConverter(Object targetObject) {
            this.targetObject = targetObject;
        }
    }
}
